【问题标题】:Need some assistance creating a Triangle class for Java需要一些帮助来为 Java 创建一个 Triangle 类
【发布时间】:2012-10-01 06:11:00
【问题描述】:

我应该为我在学校的项目制作自己的 Java Triangle 类。一个新的三角形按从左到右的顺序获取 3 个点的 (x,y) 坐标。我关心的主要是我制作 sideAB、sideBC 和 sideAC 实例变量的方式以及它们在构造函数中初始化它们的方式。此外,maxAngle 和 minAngle 看起来很乱,我希望它有 angleA、angleB 和 angleC 变量,类似于我有边的方式。另外,我不确定我的任何变量是否应该是静态的。如果我的代码真的很菜,我很抱歉,但这是我班级的第一个 Java 项目。

这就是我所拥有的。它有效,但我认为我没有以正确的方式做所有事情:

public class Triangle {
    private double ax;
    private double ay;
    private double bx;
    private double by;
    private double cx;
    private double cy;
    //added these variables because I use them so frequently when calculating angles, area, perimeter, etc.
    private double sideAB;
    private double sideBC;
    private double sideAC;

    public Triangle(double x1, double y1, double x2, double y2, double x3, double y3)
    {
        ax = x1;
        ay = y1;
        bx = x2;
        by = y2;
        cx = x3;
        cy = y3;
        sideAB= Math.abs(Math.sqrt(Math.pow(bx-ax,  2)+Math.pow(by-ay, 2)));
        sideBC= Math.abs(Math.sqrt(Math.pow(cx-bx,  2)+Math.pow(cy-by, 2)));
        sideAC= Math.abs(Math.sqrt(Math.pow(cx-ax,  2)+Math.pow(cy-ay, 2)));
    }
    public double getPerimeter()
    {
        //add the 3 sides together for the perimeter
        double perimeter = sideAB + sideBC + sideAC;
        return perimeter;
    }
    public double getArea()
    {
        //used Heron's formula to find the area of the triangle
        double s = (sideAB + sideBC + sideAC)/2;
        double area = Math.sqrt(s*(s - sideAB)*(s - sideBC)*(s - sideAC));
        return area;
    }
    public double getSideAB()
    {
        return sideAB;
    }
    public double getSideBC()
    {
        return sideBC;
    }
    public double getSideAC()
    {
        return sideAC;
    }
    public double getAngleC()
    {
        //Law of cosines to find the angle
        double a2 = Math.pow(sideAB, 2);
        double b2 = Math.pow(sideBC, 2);
        double c2 = Math.pow(sideAC, 2);
        double cosC = ((b2 + c2)-a2)/((2*sideBC)*sideAC);
        double angleC = Math.acos(cosC);
        angleC = Math.toDegrees(angleC);
        return angleC;
    }
    public double getAngleB()
    {
        double a2 = Math.pow(sideAB, 2);
        double b2 = Math.pow(sideBC, 2);
        double c2 = Math.pow(sideAC, 2);
        double cosB = ((a2+b2-c2)/(2*sideAB*sideBC));
        double angleB = Math.acos(cosB);
        angleB = Math.toDegrees(angleB);
        return angleB;
    }
    public double getAngleA()
    {
        double a2 = Math.pow(sideAB, 2);
        double b2 = Math.pow(sideBC, 2);
        double c2 = Math.pow(sideAC, 2);
        double cosA = ((a2+c2-b2)/(2*sideAB*sideAC));
        double angleA = Math.acos(cosA);
        angleA = Math.toDegrees(angleA);
        return angleA;
    }
    public double maxSide()
    {
        //if-else if-else statements for max and min sides functions
        if (sideAB >= sideBC && sideAB >= sideAC)
        {
            return sideAB;
        }
        else if(sideBC >= sideAB && sideBC >= sideAC)
        {
            return sideBC;
        }
        else
        {
            return sideAC;
        }
    }
    public double minSide()
    {
        if (sideAB <= sideBC && sideAB <= sideAC)
        {
            return sideAB;
        }
        else if(sideBC <= sideAB && sideBC <= sideAC)
        {
            return sideBC;
        }
        else
        {
            return sideAC;
        }
    }
    public double maxAngle()
    {
        double a2 = Math.pow(sideAB, 2);
        double b2 = Math.pow(sideBC, 2);
        double c2 = Math.pow(sideAC, 2);
        double cosC = ((b2 + c2)-a2)/((2*sideBC)*sideAC);
        double angleC = Math.acos(cosC);
        angleC = Math.toDegrees(angleC);
        double cosB = ((a2+b2-c2)/(2*sideAB*sideBC));
        double angleB = Math.acos(cosB);
        angleB = Math.toDegrees(angleB);
        double cosA = ((a2+c2-b2)/(2*sideAB*sideAC));
        double angleA = Math.acos(cosA);
        angleA = Math.toDegrees(angleA);
        if (angleA >= angleB && angleA >= angleC)
        {
            return angleA;
        }
        else if(angleB >= angleA && angleB >= angleC)
        {
            return angleB;
        }
        else
        {
            return angleC;
        }       
    }
    public double minAngle()
    {
        double a2 = Math.pow(sideAB, 2);
        double b2 = Math.pow(sideBC, 2);
        double c2 = Math.pow(sideAC, 2);
        double cosC = ((b2 + c2)-a2)/((2*sideBC)*sideAC);
        double angleC = Math.acos(cosC);
        angleC = Math.toDegrees(angleC);
        double cosB = ((a2+b2-c2)/(2*sideAB*sideBC));
        double angleB = Math.acos(cosB);
        angleB = Math.toDegrees(angleB);
        double cosA = ((a2+c2-b2)/(2*sideAB*sideAC));
        double angleA = Math.acos(cosA);
        angleA = Math.toDegrees(angleA);
        if (angleA <= angleB && angleA <= angleC)
        {
            return angleA;
        }
        else if(angleB <= angleA && angleB <= angleC)
        {
            return angleB;
        }
        else
        {
            return angleC;
        }       
    }
}

【问题讨论】:

  • 第一个建议 - 创建一个 Point 类(或使用现有的)来封装 (x, y) 对。这也可以计算出自身与另一点之间的距离。有六个参数来表示三个概念值是一种代码味道。
  • 没有一个答案(到目前为止)已经解决了您的坐标无法创建三角形的情况 - 这就是我想要解决的问题。

标签: java eclipse oop


【解决方案1】:

三角形的显着属性(至少在二维欧几里得空间中)是它的三个点。

就是这样,这就是您需要存储的全部。其他一切都可以据此计算。您不需要边的长度或顶点的角度,它们都可以从这三个点推导出来。

我的建议是简单地创建一个 Point 类型,然后从其中三个构建您的 Triangle 类型。

如果您确定这些派生值的计算过于昂贵,那么只有到那时,您才应该考虑缓存该信息。但我怀疑情况会如此。如果确实确实如此,那么(至少)有两种方法。

首先是在非派生值发生变化时计算派生值。这样做的好处是,当您更改某些内容并简化代码时,确保所有值都是最新的(每个 setSomething() 方法和构造函数都只需调用 calcAllDerivedValues() 方法)。

其次,您可以在更改非派生值时将派生值标记为脏值。然后,每当您需要派生数据时,计算它的方法可以检查它们是否脏,然后计算(并缓存)它们。

如果它们是脏的,它们只会返回缓存的值。这有点复杂,但可以消除不必要的计算,特别是如果每​​个派生值都有一个脏标志 - 你只计算你需要的,当你需要的时候。

而且,对于您在 static 上的具体问题,您只能使用静态类级变量,前提是它们在 所有 实例之间共享。由于边的角度或长度特定于一个实例,它们不应该是静态的。


这就是我要开始的方式。首先,一个Point 类,它具有xy 成员(以及它们的getter 和setter),并且能够计算距离和角度(相对于固定角度,如“笔直向上”)还有一点,比如:

private double x, y;

public double getX();
public double getY();
public void setX(double newX);
public void setY(double newY);
public void setXY(double newX, double newY);
public double getDistance (Point other);
public double getAngle (Point other);

那么,您的Triangle 班级需要其中三点:

private Point a, b, c;

连同适当的 setter 和 getter,以及计算所需派生属性所需的任何函数。

那会是这样的:

  • 通过计算a-&gt;bb-&gt;ca-&gt;c 之间的距离(使用PointgetDistance() 方法完成)然后添加它们来获得周长。
  • 使用相同的信息(三行长度)来获取面积。
  • 根据PointgetAngle()(例如)a-&gt;ba-&gt;c(对于角度A)的结果之间的差异获取角度。如果这个角度大于 180 度,那么显然这是三角形的外侧,你应该从 360 度中减去它以获得内角。

而且您不需要为每种情况复制所有代码。例如,您希望能够计算出三个顶点中任意一个的角度。您不需要为每个代码复制所有智能代码。

改为编写复杂的代码一次并以三种不同的方式调用它。

我的意思是这样的:

// Can just call Point stuff directly for distances (simple code).
double getDistAB() { return a.getDistance (b); }
double getDistAC() { return a.getDistance (c); }
double getDistBC() { return b.getDistance (c); }

double getPerimeter() { return getDistAB() + getDistAC() + getDistBC(); }

// Returns the angle inside triangle at the first vertex (complex code).
double getAngleAtPointX (Point x, Point y, Point z) {
    double angle = x.getAngle (y) - x.getAngle (z);
    if (angle < 0)
        angle = -angle;
    if (angle > 180)
        angle = 360 - angle;
    return angle;
}

// Then just call that with different arguments.
double getAngleA() { return getAngleAtPoint (a, b, c); }
double getAngleB() { return getAngleAtPoint (b, a, c); }
double getAngleC() { return getAngleAtPoint (c, a, b); }

【讨论】:

  • @paxdiablo.. 你好,想问一下,你是如何使用x.getAngle (y)计算角度的??你是否以horizontal line 为基础?
  • @Rohit,基线是什么并不重要,因为所有角度共享相同的基线,并且您只处理角度之间的差异:@ 987654344@。要计算角度,您只需使用三角函数,其中一个角度可以通过直角三角形的两个边长得出。您从您正在使用的线的端点制作这两条线。如果直线为(x1,y1)-(x2,y2),则直角三角形为(x1,y1)-(x2,y1)-(x2,y2)[back to (x1,y1)]
  • @paxdiablo.. 感谢您对此的解释.. 真是个好概念,在正常情况下不会想到.. :-)
【解决方案2】:

大部分情况下,代码是正确的。

不过,最大的问题是您编写的代码多次执行相同的操作。比如这个方法:

public double maxAngle()
{
    double a2 = Math.pow(sideAB, 2);
    double b2 = Math.pow(sideBC, 2);
    double c2 = Math.pow(sideAC, 2);
    double cosC = ((b2 + c2)-a2)/((2*sideBC)*sideAC);
    double angleC = Math.acos(cosC);
    angleC = Math.toDegrees(angleC);
    double cosB = ((a2+b2-c2)/(2*sideAB*sideBC));
    double angleB = Math.acos(cosB);
    angleB = Math.toDegrees(angleB);
    double cosA = ((a2+c2-b2)/(2*sideAB*sideAC));
    double angleA = Math.acos(cosA);
    angleA = Math.toDegrees(angleA);
    if (angleA >= angleB && angleA >= angleC)
    {
        return angleA;
    }
    else if(angleB >= angleA && angleB >= angleC)
    {
        return angleB;
    }
    else
    {
        return angleC;
    }       
}

计算最大角度,但您可以使用已经实现的方法 getAngleA() getAngleB()getAngleC() 来编写这样的方法:

public double maxAngle() {
  if(getAngleA() => getAngleB() && getAngleA() => getAngleC())
    return getAngleA();
  if(getAngleB() => getAngleA() && getAngleB() => getAngleC())
    return getAngleB();
  return getAngleC();
}

【讨论】:

  • @IonutHulub.. 您的方法可以通过使用条件运算符进一步改进..
【解决方案3】:

如果性能很重要,您应该预先计算所有值(假设无法更改三角形的任何点),尤其是角度,如果它们被多次访问。

不,您绝对不应该使用任何静态变量,因为这些变量将由您的 Triangle 类的每个实例共享。

【讨论】:

    【解决方案4】:

    可以在您的代码中进行的一些修改是:-

    • 创建一个Coordinate类来存储三角形三个坐标的x、y坐标。
    • 创建一个 Side 类来存储所有三个面。
    • 创建一个 Angle 类来查找和存储所有角度..

    • 现在,您不必在一个类中创建所有内容,而是可以在各自的类中计算它们..然后从那里获取..

    • E.G:-让特定的Angle实例找出它的自己的角度,你就可以得到角度从那里..所以,你不必编写逻辑来创建三次角度..

    • 您可以将您的 findMaxSide()findMinSide() 代码移动到您的 Side 类中。因为您的方法应该理想情况下是在您的方法使用的class containing the information..

    • 类似地将 findMaxAngle()findMinAngle() 移动到您的 Angle 类。

    所以,我在这里给你Angle 类,你可以使用。你可以自己创建CoordinateSide 类:-

    public class Angle {
    
        private double angle;
    
        public Angle() {
    
        }
    
        public double getAngle() {
            return this.angle;
        }
    
        public void setAngle(Side side1, Side side2, Side side3) {
    
            double a2 = Math.pow(side1.getLength(), 2);
            double b2 = Math.pow(side2.getLength(), 2);
            double c2 = Math.pow(side3.getLength(), 2);
            double cosB = ((a2+b2-c2)/(2*side1.getLength()*side2.getLength()));
    
            double tempAngle = Math.acos(cosB);
    
            this.angle = Math.toDegrees(tempAngle);
        }
    
        public Angle maxAngle(Angle angle1, Angle angle2) {
    
            Angle temp = angle1.getAngle() > angle2.getAngle() ? angle1 : angle2;
            return temp.getAngle() > this.getAngle() ? temp : this;
        }
    
        public Angle minAngle(Angle angle1, Angle angle2) {
    
            Angle temp = angle1.getAngle() < angle2.getAngle() ? angle1 : angle2;
            return temp.getAngle() < this.getAngle() ? temp : this;
        }
    }
    

    side1side2 是您要在它们之间找到角度的边..

    您可以从Triangle 类中使用这个类,如下所示:-

    public class Triangle {
    
        private Coordinate a;
        private Coordinate b;
        private Coordinate c;
        //added these variables because I use them so frequently when calculating angles, area, perimeter, etc.
    
        private Side sideAB;
        private Side sideBC;
        private Side sideAC;
    
        private Angle angleA = new Angle();
        private Angle angleB = new Angle();
        private Angle angleC = new Angle();
    
        public Triangle(double x1, double y1, double x2, double y2, double x3, double y3)
        {
    
            a = new Coordinate(x1, y1);
            b = new Coordinate(x2, y2);
            c = new Coordinate(x3, y3);
    
            sideAB= new Side(a, b);
            sideBC= new Side(b, c);
            sideAC= new Side(a, c);
    
            angleA.setAngle(sideAB, sideAC, sideBC);
            angleB.setAngle(sideAB, sideBC, sideAC);
            angleC.setAngle(sideAC, sideBC, sideAB);
        }
    
        /** Your other methods to calculate Perimeter and Area **/
    }
    

    我刚刚展示了构造函数,展示了如何设置三角形类的所有三个属性..

    我认为这么多信息将帮助您继续创建一个好的设计..

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-13
      • 1970-01-01
      • 1970-01-01
      • 2019-05-12
      • 2018-12-07
      • 1970-01-01
      • 2021-03-29
      相关资源
      最近更新 更多