Java:Coordinate Transformation - Rotation&规模

时间:2014-07-17 21:02:21

标签: java android matrix coordinates trigonometry

给定是一个旋转的矩形,它被刻在另一个矩形中 两个矩形都有自己的坐标系 在题写&旋转的矩形有一个点 P ,其坐标相对于这个矩形(红色) 想要的是这些点相对于外部矩形的坐标(绿色):
编辑:给定的还有两个矩形的宽度和高度+旋转角度

概述图片:http://i.imgur.com/QH96n7x.png

我对变换矩阵(setRotate()& setScale())的尝试失败了,而且使用三角函数我都没有使用它。

如何计算点 P 相对于外部矩形的位置?

提前致谢!

2 个答案:

答案 0 :(得分:0)

可能有点过分,但JTS(Java拓扑套件)提供了大量有用的功能来处理2D坐标。

答案 1 :(得分:0)

EDIT2:我的一位朋友指出了一个更优雅的解决方案(谢谢!)。这是:

@Override
public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint)
{
    shadowSize.set((int) width + 1, (int) height + 1);

    float x = offsetX - w / 2, y = offsetY - h / 2;
    shadowTouchPoint.x = Math.round(x * c - y * s * sFac + w / 2 + (width - w) / 2);
    shadowTouchPoint.y = Math.round(x * s * sFac + y * c + h / 2 + (height - h) / 2);
}

sFac 定义为:

float sFac = (float) Math.signum(rotationRad);

好吧,我设法用三角函数解决了这个问题 对于任何感兴趣的人,这里是我的自定义DragShadowBuilder的源代码,它在Android中用于拖放旋转缩放查看对象:

public class TargetDragShadowBuilder extends View.DragShadowBuilder
{
    ImageView view;
    float offsetX, offsetY;

    double rotationRad;
    float w;
    float h;
    double s;
    double c;
    float width;
    float height;

    public TargetDragShadowBuilder(final ImageView view, float offsetX, float offsetY)
    {
        super(view);
        this.view = view;
        this.offsetX = offsetX * view.getScaleX();
        this.offsetY = (int) (offsetY * view.getScaleY());

        rotationRad = Math.toRadians(view.getRotation());
        w = view.getWidth() * view.getScaleX();
        h = (int) (view.getHeight() * view.getScaleY());
        s = Math.abs(Math.sin(rotationRad));
        c = Math.abs(Math.cos(rotationRad));
        width = (int) (w * c + h * s);
        height = (int) (w * s + h * c);
    }

    @Override
    public void onDrawShadow(Canvas canvas)
    {
        canvas.scale(view.getScaleX(), view.getScaleY(), width / 2, height / 2);
        canvas.rotate(view.getRotation(), width / 2, height / 2);
        canvas.translate((width - view.getWidth()) / 2, (height - view.getHeight()) / 2);

        super.onDrawShadow(canvas);
    }

    @Override
    public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint)
    {
        shadowSize.set((int) width + 1, (int) height + 1);

        double x = offsetX, y = offsetY;
        if(rotationRad < 0)
        {
            final double xC = offsetX / c;
            x = xC + s * (offsetY - xC * s);
            final double yC = offsetY / c;
            y = yC + s * (w - offsetX - yC * s);
        }
        else if(rotationRad > 0)
        {
            final double xC = offsetX / c;
            x = xC + s * (h - offsetY - xC * s);
            final double yC = offsetY / c;
            y = yC + s * (offsetX - yC * s);
        }

        shadowTouchPoint.x = (int) Math.round(x);
        shadowTouchPoint.y = (int) Math.round(y);
    }
}

对于从 -90°到+ 90°的旋转有效 如果有人有更清洁或更简单的解决方案,我仍然对它感兴趣。

编辑:以下是我处理View对象丢弃的代码。

private class TargetDragListener implements OnDragListener
{
    @Override
    public boolean onDrag(View v, DragEvent e)
    {
        switch(e.getAction())
        {
            case DragEvent.ACTION_DRAG_STARTED:
                break;
            case DragEvent.ACTION_DRAG_ENTERED:
                break;
            case DragEvent.ACTION_DRAG_EXITED:
                break;
            case DragEvent.ACTION_DROP:
                if(e.getLocalState() instanceof TargetItem)
                {
                    TargetItem target = (TargetItem) e.getLocalState();
                    dropTarget(target, e.getX(), e.getY());
                }
                break;
            case DragEvent.ACTION_DRAG_ENDED:
                ((DragableItem) e.getLocalState()).setVisibility(View.VISIBLE);
            default:
                break;
        }
        return true;
    }
}

private void dropTarget(TargetItem target, float x, float y)
{
    target.setDragged(false);
    target.setVisibility(View.VISIBLE);
    target.bringToFront();

    final float scaleX = target.getScaleX(), scaleY = target.getScaleY();
    double rotationRad = Math.toRadians(target.getRotation());
    final float w = target.getWidth() * scaleX;
    final float h = target.getHeight() * scaleY;
    float s = (float) Math.abs(Math.sin(rotationRad));
    float c = (float) Math.abs(Math.cos(rotationRad));
    float sFac = (float) -Math.signum(rotationRad);

    target.offsetX *= scaleX;
    target.offsetY *= scaleY;

    x += -target.offsetX * c - target.offsetY * s * sFac;
    y += target.offsetX * s * sFac - target.offsetY * c;
    float[] pts = { x, y };
    float centerX = x + c * w / 2f + sFac * s * h / 2f;
    float centerY = y - sFac * s * w / 2f + c * h / 2f;

    transform.setRotate(-target.getRotation(), centerX, centerY);
    transform.mapPoints(pts);

    target.setX(pts[0] + (w - target.getWidth()) / 2);
    target.setY(pts[1] + (h - target.getHeight()) / 2);
}