当前位置: 首页 > 知识库问答 >
问题:

获取矩形的四个坐标,画布android

柯建修
2023-03-14

嗨,我想做一个自定义的视图,因为我正在加载位图,它有黑色的边框,右上方有关闭按钮

因此当用户按下关闭按钮时,该图像应被移除

public void draw(Canvas canvas) {
        canvas.save();

        float dx = (mMaxX + mMinX) / 2;
        float dy = (mMaxY + mMinY) / 2;

        mDrawable.setBounds((int) mMinX, (int) mMinY, (int) mMaxX, (int) mMaxY);

        canvas.translate(dx, dy);
        float rotation = mAngle * 180.0f / (float) Math.PI;
        canvas.rotate(rotation);
        canvas.translate(-dx, -dy);

        canvas.drawRect(mMinX - 10, mMinY - 10, mMaxX + 10, mMaxY + 10,
                paintBoundry);

        mDrawable.draw(canvas);
        canvas.drawCircle(mMaxX, mMinY, (mMaxX - mMinX) / 8, paintBoundry);

        canvas.restore();
    }

我已经检查了下面的链接,但无法成功

利用矩阵得到旋转后坐标的新位置

共有1个答案

梁福
2023-03-14

既然你已经有了关于旋转的信息,那就好了。现在您需要做的是将旋转矩阵应用到圆的原始中心点(正如原始的,我指的是已经平移的点,它的旋转角度是0°……您的代码中有这些信息)。从我提供的网页中可以看到,得到当前x和y值的公式如下:

x_new = x_original * Math.cos(mAngle) - y_original * Math.sin(mAngle);
y_new = x_original * Math.sin(mAngle) + y_original * Math.cos(mAngle);

注意:sincos函数采用以弧度为单位的角度参数。正如我所看到的,您正在自己进行一些转换,您可以使用Math.Todegrees(双弧度)和Math.Toradians(双度)

如果你需要的话,你可以对其他三点使用同样的原则。

  • 画布以顺时针方向旋转对象,这与数学定义旋转的方式相反。(如果你看到了这一点,并认识制造这件事的家伙,就以我的名义给他一记耳光)。要解决此问题,您必须使用负旋转角。
  • 您正在围绕视图中心旋转您的点,但您使用的是Android坐标系中的触摸值。这两个是偏移的,就像这张图片显示的(我知道,我对图片很差。对不起)

这意味着如果您将一个点从坐标系0转换为1,您将使用等式

x1=x0-view_size/2
y1=-y0+view_size/2

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;


public class RotationSquare extends View {


    private int squareBorderColor = 0xFF000000; // black
    private int innerCircleColor = 0xFFFF0000; // red
    private int outerCircleColor = 0xFF000000; // black

    private Paint squarePaint, innerCirclePaint, outerCirclePaint;
    private RectF squareRect;

    private int measuredDimenson;

    private float rotation = 0;

    // Circle parameters that should be remembered
    private float innerRadius, outerRadius, centerX, centerY;
    boolean touchedInsideCircle;


    public RotationSquare(Context context) {
        super(context);
        init(context, null, 0);
    }

    public RotationSquare(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, 0);
    }

    public RotationSquare(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr);
    }

    private void init(Context context, AttributeSet attributeSet, int defStyle) {


        squareRect = new RectF();

        squarePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        squarePaint.setColor(squareBorderColor);
        squarePaint.setStyle(Paint.Style.STROKE);

        innerCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        innerCirclePaint.setColor(innerCircleColor);
        innerCirclePaint.setStyle(Paint.Style.FILL);

        outerCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        outerCirclePaint.setColor(outerCircleColor);
        outerCirclePaint.setStyle(Paint.Style.FILL);


    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int measuredHeight = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        int measuredWidth = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);

        // Make a square
        measuredDimenson = Math.min(measuredHeight, measuredWidth);


        squareRect.set(0.25f * measuredDimenson, 0.25f * measuredDimenson, 0.85f * measuredDimenson, 0.85f * measuredDimenson);
        squarePaint.setStrokeWidth(0.025f * measuredDimenson);

        centerX = squareRect.right;
        centerY = squareRect.top;
        innerRadius = 0.07f * measuredDimenson;
        outerRadius = 0.08f * measuredDimenson;


        setMeasuredDimension((int) (measuredDimenson * 1f), (int) (measuredDimenson * 1f));
    }

    @Override
    protected void onDraw(Canvas canvas) {

        if (measuredDimenson <= 0) {
            return;
        }

        canvas.save(Canvas.MATRIX_SAVE_FLAG);

        canvas.rotate(rotation, measuredDimenson / 2, measuredDimenson / 2);

        canvas.drawCircle(centerX, centerY, outerRadius, outerCirclePaint);
        canvas.drawCircle(centerX, centerY, innerRadius, innerCirclePaint);
        canvas.drawRect(squareRect, squarePaint);
        canvas.restore();

    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX(0);
        float y = event.getY(0);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                touchedInsideCircle = isTouchInsideCircle(x, y);
                return true;
            case MotionEvent.ACTION_MOVE:
                return true;
            case MotionEvent.ACTION_UP:
                if (touchedInsideCircle && isTouchInsideCircle(x, y)) {
                    Toast.makeText(getContext(), "Clicked the circle", Toast.LENGTH_SHORT).show();
                }
                return true;
            default:
                return super.onTouchEvent(event);
        }

    }

    public void setRotation(int rotation) {
        this.rotation = rotation;
        invalidate();
    }


    private boolean isTouchInsideCircle(float x, float y) {
        double angleRad = Math.toRadians(rotation);

        // Convert to the centered coordinate system
        double centerXConverted = centerX - measuredDimenson / 2;
        double centerYConverted = -centerY + measuredDimenson / 2;

        // Use the negative angle
        double currentCenterX = centerXConverted * Math.cos(-angleRad) - centerYConverted * Math.sin(-angleRad);
        double currentCenterY = centerXConverted * Math.sin(-angleRad) + centerYConverted * Math.cos(-angleRad);

        // Convert to the centered coordinate system
        x = x - measuredDimenson / 2;
        y = -y + measuredDimenson / 2;

        double squareRadius = outerRadius * outerRadius;
        double squaredXDistance = (x - currentCenterX) * (x - currentCenterX);
        double squaredYDistance = (y - currentCenterY) * (y - currentCenterY);

        return (squaredXDistance + squaredYDistance) < squareRadius;
    }
}
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <some.package.that.you.must.change.RotationSquare
        android:id="@+id/rotatingSquare"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_centerInParent="true"/>

    <SeekBar
        android:id="@+id/seekBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:max="360"/>

    <TextView
        android:id="@+id/tvRotation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/seekBar"
        android:gravity="center_horizontal"
        android:text="Rotation: 0°"
        android:textSize="15sp"/>

</RelativeLayout>
public class MainActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener {

    private SeekBar seekBar;
    private RotationSquare rotationSquare;
    private TextView tvRotation;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        rotationSquare = (RotationSquare) findViewById(R.id.rotatingSquare);
        seekBar = (SeekBar) findViewById(R.id.seekBar);
        seekBar.setOnSeekBarChangeListener(this);

        tvRotation = (TextView) findViewById(R.id.tvRotation);
    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
        rotationSquare.setRotation(i);
        tvRotation.setText("Rotation: " + i + "°");
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {

    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {

    }
}

希望我没有用数学和这些方程式把你吓跑:/

 类似资料:
  • 如何获得旋转矩形的角坐标(以矩形为中心)? 我已经尝试了以下链接中的所有解决方案,但似乎没有任何运气。 将一个点绕另一个点旋转(2D) 找到给定中心点和旋转的旋转矩形的角 https://game dev . stack exchange . com/questions/86755/how-to-calculate-corner-positions-marks-of-a-rotated-tilte

  • 在上面的图片中,我展示了两个矩形 矩形1,其x可以从-900到13700不等,Y可以从-600到6458 矩形2,其坐标X可以从0到3000变化,而y可以从0到2000变化 同样:矩形2的起点位于左上角位置(0,0),而矩形1的起点位于左上角位置(宽度/2,高度/2)。 我需要做的是:使用缩放或平移将矩形1的点转换为矩形2的点。 那么,为了将矩形1的坐标转换为矩形2的坐标,< code>x和< c

  • 我有一个非常大的矩形(100,000x100,000),我试图在上面随机放置许多不同大小的圆。我目前的解决方案是将以前使用的所有坐标对存储在一个地图中,然后随机生成一个新的对,并检查它是否存在于地图中。 因为我生成了很多坐标,所以这个方法会变得有点慢。有没有一个更好,最重要的是更快的方法来得到矩形上的随机坐标,也许也有一个方法来得到它们而不是圆重叠?

  • 我需要点子,这不是家庭作业...... 我有下面的矩阵,我如何获得重复数字的坐标, 重复项[[[0,0],[1,0],[2,0],[0,1],[0,1],[0,2],[1,2],[1,3],[2,2]],[[0,3],[0,4],.........] 第1组,分离2组,分离3组,仅2组 重复项[[[0,0],[1,0],[2,0],[0,1],[0,2],[1,2],[1,3],[2,2]],[[

  • 我应该自己写方法吗?尽管我害怕不能解释一些事情,因为我的数学已经生疏了。或者我能为Java找到一个现成的实现吗?我有谷歌地图sdk在我的项目,但我找不到任何有用的东西。

  • 我试图创建一个画布,在其中我们可以绘制直线和矩形使用鼠标事件的功能选择的输入。 我将mousedown、mousemove和mouseup事件侦听器附加到画布DOM,并在选择行输入或矩形输入时使用适当的函数 但它什么也没有画出来。 null null