11

グラフのプロットに小さな問題があります。下の写真は、私がすでに行ったことです。


グラフは、利用可能な 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);

写真の例は、dB 変化の動的シミュレーションです。すべてが正しく機能すると思いますが、私が達成したいのは、「丸みを帯びた」角を持つ線を作成することです (意味を確認するには、図を参照してください)。

私はすでに LineFormatter をカスタマイズしようとしました:

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

しかし、これは期待どおりに機能しませんでした。

ここに画像の説明を入力してください

注: Wifi アナライザーアプリケーションにも同様のグラフがあり、そのグラフには希望どおりの角が丸くなっています。次のようになります。

ここに画像の説明を入力してください

4

6 に答える 6

12

Path.cubicTo()メソッドを使用できます。3 次スプライン アルゴリズムを使用して線を描画し、必要な平滑化効果をもたらします。

男が3次スプラインについて話している同様の質問への回答をチェックアウトしてください。メソッドの入力パラメータを計算する方法を示す短いアルゴリズムがありますPath.cubicTo()。分割値をいじって、必要な滑らかさを実現できます。たとえば、下の図では、3 ではなく 5 で割っています。これがお役に立てば幸いです。

Path.cubicTo() メソッドを使用して描画されたポリリンの例

私はしばらく時間をかけてSplineLineAndPointFormatterクラスを実装しました。これは、androidplot ライブラリで必要なことを行います。それは同じ技術を使用します。androidplot のサンプル アプリケーションは次のようになります。の代わりに使用するだけですLineAndPointFormatter

SplineLineAndPointFormatter を使用した Androidplot の例

これがコード例と私が書いたクラスです。

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);
        }
    }
}
于 2013-08-21T09:18:11.993 に答える
0

チャートエンジンを使用して ChartFactory.getLineChartView の代わりに ChartFactory.getCubeLineChartView を使用するだけです

于 2016-03-09T07:10:09.787 に答える
0

Androidplot には常にスムーズ ライン レンダラーがあります: BezierLineAndPointRenderer は、上記の実装と同様に、Android に組み込まれている Bezier 描画ルーチンcubeTo(...) & quadTo(...)を使用します。問題は、このようにベジエを使用して滑らかな線を描くと、実際のコントロール ポイントをさまざまな量だけオーバーシュートする誤った線が作成されることです。これは、上の画像をよく見ると発生していることがわかります。

解決策は、Androidplot で最終的にサポートされるようになった Catmull-Rom スプライン補間を使用することです。詳細はこちら: http://androidplot.com/smooth-curves-and-androidplot/

于 2014-09-26T14:05:57.073 に答える