0

学校でのプロジェクト用に、独自の Java Triangle クラスを作成することになっています。新しい Triangle は、左から右の順に 3 点の (x,y) 座標を取得します。私の懸念は主に、sideAB、sideBC、および sideAC インスタンス変数を作成し、コンストラクターでそれらを初期化する方法にあります。また、maxAngle と minAngle は混乱しているように見えます。また、私の変数のいずれかが静的であると想定されているかどうかはわかりません。私のコードが本当に初歩的で申し訳ありませんが、これは私のクラスの最初の 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;
        }       
    }
}
4

4 に答える 4

2

(少なくとも 2 次元のユークリッド空間では) 三角形の顕著な特性は、その 3 つの点です。

それだけです。保存する必要があるのはそれだけです。他のすべてはそこから計算できます。辺の長さや頂点の角度は必要ありません。それらはすべて、これらの 3 点から導き出すことができます。

私のアドバイスは、単純にタイプを作成し、そのうちの 3 つからタイプPointを構築することTriangleです。

これらの派生値の計算が高すぎることがわかった場合は、そのときだけ、その情報をキャッシュすることを検討する必要があります。しかし、そうなるとは思えません。その場合、(少なくとも) 2 つのアプローチがあります

1 つ目は、非派生値が変化するたびに派生値を計算することです。これには、何かを変更するたびにすべての値が最新であることを保証し、コードが簡素化されるという利点があります (すべてsetSomething()のメソッドとコンストラクターはcalcAllDerivedValues()メソッドを呼び出すだけです)。

次に、非派生値を変更するたびに、派生値をダーティとしてマークできます。その後、派生データが必要なときはいつでも、それを計算するメソッドはそれらがダーティかどうかをチェックし、そうであれば計算 (およびキャッシュ) します。

ダーティーでない場合は、単にキャッシュされた値を返します。これはもう少し複雑ですが、不要な計算を削除できます。特に、派生値ごとにダーティ フラグが 1 つある場合は、必要なときに必要なものだけを計算します。

また、特定の質問については、すべてのインスタンスstatic間で共有されている場合にのみ、静的クラスレベルの変数を使用してください。側面の角度または長さは1 つのインスタンスに固有であるため、静的であってはなりません。


これが私が始める方法です。まず、メンバーと (ゲッターとセッターを含む)Pointを持つクラスと、次のような別のポイントまでの距離と角度 (「まっすぐ」などの固定角度に対する相対角度) を計算する機能:xy

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クラスには次の 3 つのポイントが必要です。

private Point a, b, c;

適切なセッターとゲッター、および目的の派生プロパティを計算するために必要な関数と共に。

それは次のようなものです:

  • a->bと の間の距離を計算して周囲を取得しb->c(a->cクラス メソッドで実行Point) getDistance()、それらを追加します。
  • 同じ情報 (3 つの線の長さ) を使用して面積を取得します。
  • (例として)と(角度 A)のPointクラスの結果の違いに基づいて角度を取得します。この角度が 180 より大きい場合、それは明らかに三角形の外側であり、360 からそれを減算して内側の角度を取得する必要があります。getAngle()a->ba->c

また、状況ごとにすべてのコードを複製する必要はありません。たとえば、3 つの頂点のいずれかで角度を計算できるようにします。それぞれのインテリジェント コードをすべて複製する必要はありません。

代わりに、その複雑なコードを 1 回記述し、それを 3 つの異なる方法で呼び出します。

つまり、次のような意味です。

// 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); }
于 2012-10-01T06:18:28.953 に答える
1

ほとんどの場合、コードは正しいです。

ただし、最大の問題は、同じことを複数回実行するコードを作成することです。たとえば、この方法:

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();
}
于 2012-10-01T06:21:53.053 に答える
0

コードで実行できる変更の一部は次のとおりです。 -

  • 三角形の 3 つの座標の x、y 座標を格納するCoordinateクラスを作成します。
  • 3 つの面すべてを格納するSideクラスを作成します。
  • すべての角度を見つけて保存するために、 Angleクラスを作成します。

  • 1 つのクラスですべてを作成するのではなく、それぞれのクラスで計算することができます..そして、そこからフェッチするだけです..

  • EG: -特定のインスタンスに独自の角度Angleを見つけさせ、そこから角度を取得するだけです..したがって、角度を作成するロジックを 3 回記述する必要はありません..

  • findMaxSide()、およびfindMinSide()コードをSideクラスに移動できます。メソッドは、理想的にはclass containing the information、メソッドが使用している にある必要があるためです。

  • 同様にfindMaxAngle()andをAngleクラスに移動findMinAngle()します。

だから、ここで私は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 **/
}

三角形クラスの 3 つの属性すべてを設定する方法を示すコンストラクターを示しました。

これだけの情報は、良いデザインを作成するために前進するのに役立つと思います..

于 2012-10-01T06:44:37.100 に答える
0

パフォーマンスが重要な場合は、すべての値 (三角形のどの点も変更できないと仮定して) を事前に計算する必要があります。特に、複数回アクセスする場合は角度を計算する必要があります。

いいえ、静的変数は Triangle クラスのすべてのインスタンスで共有されるため、絶対に使用しないでください。

于 2012-10-01T06:23:10.550 に答える