用两点画等腰triangle/arrow

Drawing an isosceles triangle/arrow with two points

我想弄清楚这个问题已经有一段时间了,我正在制作一个使用三角形作为箭头的程序,并试图弄清楚如何用两个点制作一个箭头,这意味着第一个点位于三角形底部的中点,而第二个点位于远离第一个点的方向的尖端。

这张粗画应该有助于弄清楚我在说什么 http://i.stack.imgur.com/f3ktz.png(会放直接图片但没有足够的代表)

现在,我仔细研究并尝试弄清楚如何计算三角形的其他两个端点,这样我就可以制作多边形,但我做的不正确,因为我得到的三角形不是等腰的,端点不会创建垂直于原始线的线。

我目前得到的(用一些图来显示要点) http://i.stack.imgur.com/dljsn.png

我当前的代码

public class Triangle extends Shape{

private boolean assigned = false;

private int[] x;

private int[] y;

public Triangle(Point startPoint, Point endPoint){
    this.startPoint = startPoint;
    this.endPoint = endPoint;
}

@Override
public void draw(Graphics g) {
    g.setColor(Color.white);
    if(!assigned) {
        x = new int[3];
        y = new int[3];
        double distance = startPoint.distance(endPoint);
        double halfDistance = distance/2;
        double angle = getAngle(startPoint,endPoint)- Math.PI/2.0;

        x[0] = (int)endPoint.getX();
        y[0] = (int)endPoint.getY();

        x[1] = (int)((Math.sin(angle)*halfDistance) + startPoint.getX());
        y[1] = (int)((Math.cos(angle)*halfDistance) + startPoint.getY());

        x[2] = (int)(startPoint.getX() - (Math.sin(angle)*halfDistance));
        y[2] = (int)(startPoint.getY() - (Math.cos(angle)*halfDistance));


        assigned = true;
        if(endPoint.distance(x[1],y[1]) == (Math.sqrt(5)*halfDistance))
            System.out.println("DEBUG: Confirm Correct 1");
        if(endPoint.distance(x[1],y[1]) == endPoint.distance(x[2],y[2]))
            System.out.println("DEBUG: Confirm Correct 2");
    }
    g.fillPolygon(x,y,3);
    g.setColor(Color.blue);
}

private double getAngle(Point pointOne, Point pointTwo){
    double angle = Math.atan2(pointTwo.getY()- pointOne.getY(),pointTwo.getX()-pointOne.getX());
    while(angle < 0){
        angle += (2.0*Math.PI);
    }
    return angle;
}

}

我已经为此工作了几个小时,但似乎无法弄清楚,请有人帮忙。

所以,我最终用 double angle = -Math.atan2(endPoint.y - startPoint.y, endPoint.x - startPoint.x);

替换了 double angle = getAngle(startPoint,endPoint)- Math.PI/2.0;

我编写了这个小测试程序,它允许您移动到圆周周围的点并生成生成的三角形...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                TestPane tp = new TestPane();
                JPanel control = new JPanel(new BorderLayout());
                control.add(tp);

                final JSlider startAngel = new JSlider(0, 359);
                final JSlider endAngel = new JSlider(0, 359);

                JPanel sliders = new JPanel(new GridLayout(1, 2));
                sliders.add(startAngel);
                sliders.add(endAngel);

                startAngel.addChangeListener(new ChangeListener() {
                    @Override
                    public void stateChanged(ChangeEvent e) {
                        tp.setStartAngle(startAngel.getValue());
                    }
                });
                endAngel.addChangeListener(new ChangeListener() {
                    @Override
                    public void stateChanged(ChangeEvent e) {
                        tp.setEndAngle(endAngel.getValue());
                    }
                });

                startAngel.setValue(0);
                endAngel.setValue(180);

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(control);
                frame.add(sliders, BorderLayout.SOUTH);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private Point startPoint, endPoint;
        private float startAngle = 0;
        private float endAngle = 180;

        public TestPane() {
        }

        @Override
        public void invalidate() {
            super.invalidate();
            recalculate();
        }

        protected void recalculate() {

            int dim = Math.min(getWidth(), getHeight());
            dim -= 50;
            float radius = dim / 2f;

            startPoint = getPointOnCircle(startAngle, radius);
            endPoint = getPointOnCircle(endAngle, radius);

            repaint();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        protected Point getPointOnCircle(float degress, float radius) {

            int x = Math.round(getWidth() / 2);
            int y = Math.round(getHeight() / 2);

            double rads = Math.toRadians(degress - 90); // 0 becomes the top

            // Calculate the outter point of the line
            int xPosy = Math.round((float) (x + Math.cos(rads) * radius));
            int yPosy = Math.round((float) (y + Math.sin(rads) * radius));

            return new Point(xPosy, yPosy);

        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();

            int[] x = new int[3];
            int[] y = new int[3];
            double distance = startPoint.distance(endPoint);
            double halfDistance = distance / 2;
            double angle = -Math.atan2(endPoint.y - startPoint.y, endPoint.x - startPoint.x);

            System.out.println(angle);

            x[0] = (int) endPoint.getX();
            y[0] = (int) endPoint.getY();

            x[1] = (int) ((Math.sin(angle) * halfDistance) + startPoint.getX());
            y[1] = (int) ((Math.cos(angle) * halfDistance) + startPoint.getY());

            x[2] = (int) (startPoint.getX() - (Math.sin(angle) * halfDistance));
            y[2] = (int) (startPoint.getY() - (Math.cos(angle) * halfDistance));

            g2d.setColor(Color.RED);
            g2d.fillPolygon(x, y, 3);

            g2d.setColor(Color.BLUE);
            g2d.fillOval(startPoint.x - 5, startPoint.y - 5, 10, 10);
            g2d.setColor(Color.GREEN);
            g2d.fillOval(endPoint.x - 5, endPoint.y - 5, 10, 10);

            g2d.dispose();
        }

        public void setStartAngle(float value) {
            startAngle = value;
            recalculate();
        }

        public void setEndAngle(float value) {
            endAngle = value;
            recalculate();
        }

    }

}

如果这仍然给你一些奇怪的结果,除了分享一些测试数据,我可能会考虑使用像 Math.atan2(Math.abs(endPoint.y - startPoint.y), Math.abs(endPoint.x - startPoint.x)) 或 simular

这样的东西

你根本不需要计算角度。

    double startX = 40;
    double startY = 120;
    double endX = 110;
    double endY = 15;

    double deltaX =  ( startY - endY ) / 2;
    double deltaY =  ( endX - startX ) / 2;

    double[] polygonX = new double[3];
    double[] polygonY = new double[3];

    polygonX[0] = endX;
    polygonY[0] = endY;

    polygonX[1] = startX - deltaX;
    polygonY[1] = startY - deltaY;

    polygonX[2] = startX + deltaX;
    polygonY[2] = startY + deltaY;

画得非常糟糕 :D,但重点是:

cos(ang) = 'distance' / ( startY - endY )cod(ang) = ('distance'/2) / deltaX 所以 deltaX = ( startY - endY ) / 2

同样适用于deltaY = ( endX - startX ) / 2

所以三角形的另外 2 个点将是 startPoint 减去和加上那些增量。