gpt4 book ai didi

java - 基于点的曲线变换。 Android 中的贝塞尔曲线变换

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:57:14 25 4
gpt4 key购买 nike

我有一个点列表,代表我使用 Path 对象在 Canvas 上绘制的曲线。

path.moveTo(x, y);
for (int i = 0; i < points.size(); i++) {
path.lineTo(points.get(i).x, points.get(i).y);
}
canvas.drawPath(path, paint);

我想要实现的是能够设置用户可以触摸和移动的控制点,并根据该移动我的点进行转换。与 photoshop 使用 钢笔工具 做的事情相同,请参见图片: enter image description here

注意:android Path只用于绘图,我不需要修改Path我需要修改坐标。所以上面的代码可以替换为

canvas.drawLine();

它与 Path 对象无关。

最佳答案

这是使用一个“ anchor ”和两个控制点的简单 View ,如果您需要更多 anchor ,请将另一个 cubicTo 添加到您的路径中:

class V extends View {
static final float RADIUS = 32;
Path path = new Path();
Paint pathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
Paint controlPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
PointF ctrl1 = new PointF();
PointF ctrl2 = new PointF();
PointF ctrl3 = new PointF();
PointF ctrl4 = new PointF();
PointF anchor = new PointF();
GestureDetector detector;
Layout layout;

public V(Context context) {
super(context);
pathPaint.setColor(Color.RED);
pathPaint.setStyle(Paint.Style.STROKE);
pathPaint.setStrokeWidth(16);
controlPaint.setColor(Color.GREEN);
controlPaint.setAlpha(128);
detector = new GestureDetector(context, listener);
}

GestureDetector.OnGestureListener listener = new GestureDetector.SimpleOnGestureListener() {
PointF target;

@Override
public boolean onDown(MotionEvent e) {
PointF[] targets = { ctrl2, ctrl3, anchor };
for (PointF t : targets) {
if (Math.hypot(t.x - e.getX(), t.y - e.getY()) < RADIUS) {
target = t;
return true;
}
}
target = null;
return false;
}

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (target == null) return false;

target.offset(-distanceX, -distanceY);
if (target == ctrl2 || target == ctrl3) {
PointF otherControl = target == ctrl2 ? ctrl3 : ctrl2;
// anchor just between points
double a = Math.atan2(anchor.y - target.y, anchor.x - target.x);
double r = Math.hypot(otherControl.x - anchor.x, otherControl.y - anchor.y);
otherControl.set((float) (anchor.x + r * Math.cos(a)), (float) (anchor.y + r * Math.sin(a)));

// anchor always in the center
// otherControl.set(2 * anchor.x - target.x, 2 * anchor.y - target.y);
} else {
ctrl2.offset(-distanceX, -distanceY);
ctrl3.offset(-distanceX, -distanceY);
}
rebuildPath();
invalidate();
return true;
}
};

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
ctrl1.set(w * 0.0f, h * 1.0f);
ctrl2.set(w * 0.1f, h * 0.5f);
ctrl3.set(w * 0.9f, h * 0.5f);
ctrl4.set(w * 1.0f, h * 1.0f);
anchor.set(w * 0.5f, h * 0.5f);
rebuildPath();
CharSequence src = "you can drag any green circle: the both control points or the anchor point\n\n" +
"notice that the control points can be adjusted individually - the only constraint for a smooth line is that the anchor point is between them (but not necessarily in the exact center)";
TextPaint tp = new TextPaint();
tp.setColor(Color.WHITE);
tp.setTextSize(32);
layout = new StaticLayout(src, tp, w - 64, Layout.Alignment.ALIGN_NORMAL, 1, 0, true);
}

private void rebuildPath() {
path.reset();
path.moveTo(ctrl1.x, ctrl1.y);
path.cubicTo(ctrl1.x, ctrl1.y, ctrl2.x, ctrl2.y, anchor.x, anchor.y);
path.cubicTo(ctrl3.x, ctrl3.y, ctrl4.x, ctrl4.y, ctrl4.x, ctrl4.y);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
detector.onTouchEvent(event);
return true;
}

@Override
protected void onDraw(Canvas canvas) {
canvas.save();
canvas.translate(32, 32);
layout.draw(canvas);
canvas.restore();
canvas.drawPath(path, pathPaint);
controlPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(anchor.x, anchor.y, RADIUS, controlPaint);
canvas.drawCircle(ctrl2.x, ctrl2.y, RADIUS, controlPaint);
canvas.drawCircle(ctrl3.x, ctrl3.y, RADIUS, controlPaint);
controlPaint.setStyle(Paint.Style.STROKE);
canvas.drawLine(ctrl2.x, ctrl2.y, ctrl3.x, ctrl3.y, controlPaint);
}
}

关于java - 基于点的曲线变换。 Android 中的贝塞尔曲线变换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44613114/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com