android.graphics. cornerpatheeffect是如何工作的?



我想将android.graphics.Path转换为svg路径数据。我写了一个剧本,效果很好,但台词不像原来那样流畅。

转换前(android.graphics。绘制在Canvas对象上的路径)

转换后(生成。svg文件)

我怎么能解决这个问题?

下面是我的代码:
private String createPathData(android.graphics.Path path){

List<PointF> points = getPoints(path);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("M ")
.append((int) points.get(0).x)
.append(" ")
.append((int) points.get(0).y)
.append(" ");
for (int i = 0; i < points.size() - 4; i += 4) {
float lastX = (int) points.get(i).x;
float lastY = (int) points.get(i).y;
float x = (int) points.get(i + 4).x;
float y = (int) points.get(i + 4).y;
//Creates bezier curve
stringBuilder.append("C ");
stringBuilder
.append((int) x).append(" ").append((int) y).append(" ") //start point
//Here is the problem.
//There I should include CornerPathEffect in the formula, but don't know how.
.append((int) (lastX + x) / 2).append(" ").append((int) (lastY + y) / 2).append(" ") //control point
.append((int) lastX).append(" ").append((int) lastY).append(" "); //end point
}
return stringBuilder.toString();
}

这是getPoints()方法

public static List<PointF> getPoints(Path path){
PathMeasure pathMeasure = new PathMeasure(path, false);
List<PointF> res = new ArrayList<>();
for (int i = 0; i < pathMeasure.getLength(); i+=4) {
float[] coordinates = new float[]{0, 0};
pathMeasure.getPosTan(i, coordinates, null);
res.add(new PointF(coordinates[0], coordinates[1]));
}
return res;
}

然后我插入结果到d属性在svg<path>,我得到这样的东西:

<path d="M 200 184 C 184 185 192 184 200 184 C 170 193 177 189 184 185 C 158 203 164 198 (...)/>
下面是我生成的完整svg: Link

我是这样画的

//Creating a path
smartOnTouchEventListener.setOnTouchEventListener(new STouchListener.OnTouchEvent() {
@Override
public void onTouchStarted(int fingers, PointF[] points) {
/*
* Line is new. Starts line.
*/
currentPath.moveTo(points[0].x, points[0].y);
lastX = points[0].x;
lastY = points[0].y;
}
@Override
public void onMove(int fingers, PointF[] points) {
//User draggs his finger and creates the path.
float dx = Math.abs(points[0].x - lastX);
float dy = Math.abs(points[0].y - lastY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
currentPath.quadTo(lastX, lastY, (points[0].x + lastX) / 2, (points[0].y + lastY) / 2);
lastX = translateX(points[0].x);
lastY = translateY(points[0].y);
}
//Here I draw a path
...
}
@Override
public void onTouchEnd(int fingers, PointF[] points) {
/*
User ends new line.
*/
//Here I save the path
...
currentPath.reset();

}
});
//Drawing a path
Paint pen = new Paint();
pen.setAntiAlias(true);
pen.setColor(getPenColor());
pen.setStyle(Paint.Style.STROKE);
pen.setStrokeJoin(Paint.Join.ROUND);
pen.setStrokeCap(Paint.Cap.ROUND);
pen.setDither(true);
//I think this is the reason of difference between the original and generated one, 
//but can't find a source code of android.graphics.CornerPathEffect
pen.setPathEffect(new CornerPathEffect(10));
pen.setStrokeWidth(getPenSize());
pen.setXfermode(getPenMode()));
pen.setAlpha(getPenAlpha());
canvas.drawPath(path, pen);

提前感谢!

我认为原始代码的主要问题是如何重建路径。我不知道你为什么在这里使用贝塞尔曲线:

stringBuilder.append("C ");
stringBuilder
.append((int) x).append(" ").append((int) y).append(" ") //start point
.append((int) (lastX + x) / 2).append(" ").append((int) (lastY + y) / 2).append(" ")
.append((int) lastX).append(" ").append((int) lastY).append(" "); //end point
你把你的控制点弄混了。贝塞尔曲线(C)路径命令中的三个点是:
C <first control point> <second control point> <end point>

但你似乎在做:

C <end point> <halfway point> <start point>

这将导致一个非常混乱的行,我想。你最好画一条直线。

stringBuilder.append("L ");
stringBuilder.append((int) x).append(" ").append((int) y).append(" ")

顺便说一句,你在生成原始路径时也犯了同样的错误。参数是反向的

currentPath.quadTo(lastX, lastY, (points[0].x + lastX) / 2, (points[0].y + lastY) / 2);

应:

currentPath.quadTo((points[0].x + lastX) / 2, (points[0].y + lastY) / 2, points[0].x, points[0].y);

但是这也会创建一个直线段。这是因为你的控制点被设置为中间点。这和

是一样的
currentPath.lineTo(points[0].x, points[0].y);

但是为什么要在之后重新创建路径呢?为什么不与原始路径同时生成SVG路径呢?

smartOnTouchEventListener.setOnTouchEventListener(new STouchListener.OnTouchEvent() {
@Override
public void onTouchStarted(int fingers, PointF[] points) {
/*
* Line is new. Starts line.
*/
currentPath.moveTo(points[0].x, points[0].y);
currentSVG += "M " + points[0].x + " " + points[0].y + " ";
lastX = points[0].x;
lastY = points[0].y;
}
@Override
public void onMove(int fingers, PointF[] points) {
//User draggs his finger and creates the path.
float dx = Math.abs(points[0].x - lastX);
float dy = Math.abs(points[0].y - lastY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
currentPath.lineTo(points[0].x, points[0].y);
currentSVG += "L " + points[0].x + " " + points[0].y + " ";
lastX = translateX(points[0].x);
lastY = translateY(points[0].y);
}
//Here I draw a path
...
}
@Override
public void onTouchEnd(int fingers, PointF[] points) {
/*
User ends new line.
*/
//Here I save the path
...
currentPath.reset();

}
});

至于你的patheeffect…你不应该需要它。我怀疑你添加它是为了让这条路更平坦。修正你的参数顺序,或者切换到直线段可以解决这个问题。

最新更新