Как сделать линию с закругленными (гладкими) углами с AndroidPlot

У меня небольшая проблема с построением графика. На картинке ниже – это то, что я уже сделал.


График должен представлять фактическую силу сигнала в доступных сетях Wi-Fi. Это простой XYPlot здесь данные представлены с помощью SimpleXYSeries (значения динамически создаются).

Вот небольшой фрагмент кода (только для примера):

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

Примером на рисунке является динамическое моделирование изменений дБ. Все работает, я думаю, правильно, но я хочу достичь линии с закругленными углами (см. Рисунок, чтобы понять, что я имею в виду).

Я уже пытался настроить LineFormatter:

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

Но это не сработало, как ожидалось.

Введите описание изображения здесь

Примечание. Приложение Wifi Analyzer имеет аналогичный граф, и его график имеет округлые углы, которые я хочу. Это выглядит так:

Введите описание изображения здесь

Solutions Collecting From Web of "Как сделать линию с закругленными (гладкими) углами с AndroidPlot"

Вы можете использовать метод Path.cubicTo () . Он рисует линию, используя алгоритм кубического сплайна, который дает эффект сглаживания, который вы хотите.

Оформить ответ на аналогичный вопрос здесь , где парень говорит о кубических сплайнах. Существует короткий алгоритм, показывающий, как вычислять входные параметры для Path.cubicTo() . Для достижения требуемой гладкости вы можете играть с разделителями. Например, на рисунке ниже я разделил 5 вместо 3. Надеюсь, это поможет.

Пример полилины, нарисованной методом Path.cubicTo ()

Я провел некоторое время и внедрил класс SplineLineAndPointFormatter , который делает материал, который вам нужен в библиотеке androidplot. Он использует ту же технику. Вот как выглядит приложение приложений androidplot. Вам просто нужно использовать его вместо LineAndPointFormatter .

Пример Androidplot с SplineLineAndPointFormatter

Вот пример кода и класс, который я написал.

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

Вот класс, делающий магию. Он основан на версии 0.6.1 библиотеки androidplot .

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

1- Думаю, вы используете только несколько точек для рисования графиков сигналов. Все приложения графика / диаграммы пытаются подключить точки с прямыми линиями, а затем отобразится ваша диаграмма. Поэтому, если вы используете только три точки, ваш график будет выглядеть как треугольник! Если вы хотите, чтобы ваш график был изогнутым, вам нужно добавить больше очков. Затем он выходит как кривая.

2- Или вы можете найти любую библиотеку, которая может рисовать график sin , например GraphView Library . Затем попробуйте сделать эту функцию:

Введите описание изображения здесь

Так выглядит:

Введите описание изображения здесь

Затем переведите его на (a,0) , поэтому результат будет похож на то, что вы хотите.

3- И по-другому, вы можете использовать встроенный Math.sin в Java:

Выберите, например, 1000 точек в диапазоне от a до b и вычислите значение выше функции для каждой точки и, наконец, создайте path и покажите их на холсте.

Вы можете использовать quadTo (float x1, float y1, float x2, float y2), которые упрощают рисование quad curves для вас. В документации говорится:

Добавьте квадратичную безье от последней точки, приближаясь к контрольной точке (x1, y1) и заканчивая на (x2, y2). Если для этого контура не было сделано никакого вызова moveTo (), первая точка автоматически устанавливается на (0,0).

параметры

X1 Координата x контрольной точки на квадратичной кривой
Y1 У-координата контрольной точки на квадратичной кривой
X2 Координата x конечной точки на квадратичной кривой
Y2. У-координата конечной точки на квадратичной кривой

Наконец, я добавляю простой класс, который расширяет 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); } } 

Результат должен выглядеть так:

Введите описание изображения здесь

Вы можете добавить дополнительные методы в класс и изменить его для повышения производительности!

В Androidplot всегда есть плавный линейный рендеринг: BezierLineAndPointRenderer, который, как и вышеприведенные реализации, использует встроенные в Android алгоритмы рисования Buzier cubTo (…) & quadTo (…) . Проблема заключается в том, что использование Beziers для рисования гладких линий таким образом создает ложную линию, которая перерегулирует фактические контрольные точки в разных количествах, что вы можете видеть, если внимательно посмотрите на изображение выше.

Решением является использование сплайновой интерполяции Catmull-Rom, которая теперь, наконец, поддерживается Androidplot. Подробности здесь: http://androidplot.com/smooth-curves-and-androidplot/

Просто используйте ChartFactory.getCubeLineChartView вместо ChartFactory.getLineChartView, используя движок achart

попробуй это:

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

Большая часть информации, найденной здесь