Question

I need to make a Class named "TriangleShape" which impliments java.awt.Shape. Now another Class "TriangleComponent" should have an object of TriangleShape class and it should draw a triangle, with the given length of sides.

I managed to create it, but i've read that the triangle should be drawn in the following way:

TriangleShape t = new TriangleShape(30,40,50);
g2.draw(t);         //This is the Graphics2D object that I use in paintComponent

The following is the code that I created, but it uses Line2D to create a triangle. It is the TriangleShape class, assume that I have implimented all the methods of the Shape Class.

public class TriangleShape implements java.awt.Shape{

private double a, b, c;
private int x,y;
private Point2D loc;

public TriangleShape() {
    this.a=0;
    this.b=0;
    this.c=0;
}

public TriangleShape(double a, double b, double c) {
    //if supplied dimensions form a valid Triangle
    if ( this.isValid(a,b,c) ) {
        this.a = a;
        this.b = b;
        this.c = c;        
    }
    //Otherwise make it zero sized triangle
    else{
        this.a=0;
        this.b=0;
        this.c=0;
    }            
}

public void resize(double a, double b, double c) {
    if ( this.isValid(a,b,c) ) {
        this.a = a;
        this.b = b;
        this.c = c;        
    }
    //else let size remain unchanged
}

public TriangleShape getRandomTriangle() {
    TriangleShape t = new TriangleShape(5,8,9);
    return t;
}

public double area(){
    double area, s;
    s = (a+b+c)/2;
    area = Math.sqrt(s *(s-a) * (s-b) * (s-c));
    return area;
}

private boolean isValid(double a, double b, double c) {
    double s = (a+b+c)/2;
    if ( ((s-a) * (s-b) * (s-c)) <= 0 )
        return false;
    else
        return true;
}

public double perimeter() {
    double p;
    p = a+b+c;
    return p;
}

public double getA(){
    return a;
}
public double getB(){
    return b;
}
public double getC(){
    return c;
}

public void setLocation(Point2D location){
loc = location;
}

public Point2D getLocation(){
return loc;
}

public double getX(){
return loc.getX();
}

public double getY(){
return loc.getY();
}

And the TriangleComponent class:

public class TriangleComponent extends JComponent{

TriangleShape t;
double alpha, beta, gamma;
double a,b,c;
double X,Y;

@Override
protected void paintComponent(Graphics g) {
//super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
t = new TriangleShape(100,100,190);
t.setLocation(new Point2D.Double(100,500));
a = t.getA();
b = t.getB();
c = t.getC();

X = t.getX();
Y = t.getY();

///////////////Drawing Base line.....

g2.draw(new Line2D.Double(X,Y,(X+c),Y));    //line c...
g2.draw(new Line2D.Double((X+c), Y, ((X+c)+a*Math.cos(Math.PI+getBeta())), (Y+a*Math.sin(Math.PI+getBeta())))); //line a...


//JOIning the last end points
g2.draw(new Line2D.Double(X, Y, ((X+c)+a*Math.cos(Math.PI+getBeta())), (Y+a*Math.sin(Math.PI+getBeta()))));


System.out.println("X1 = "+X+"  Y1 = "+Y);
System.out.println("X2 = "+(X+c)+"  Y2 = "+Y);  
System.out.println("X3 = "+((X+c)+a*Math.cos(Math.PI+getBeta()))+" Y3 = "+ (Y+a*Math.sin(Math.PI+getBeta())));
//System.out.println("Alpha = "+getAlpha());
System.out.println("Gamma = "+(getGamma()*180)/Math.PI);
}

public double getAlpha(){
double temp = Math.acos(((Math.pow(c, 2)+Math.pow(b, 2))-Math.pow(a, 2))/(2*b*c));
System.out.println("Alpha = "+temp+" Degrees");
return temp;
}

public double getBeta(){
double temp = Math.acos(((Math.pow(c, 2)+Math.pow(a, 2))-Math.pow(b, 2))/(2*a*c));
System.out.println("Beta = "+temp+" Degrees");
return (temp);// * Math.PI)/180;
}

public double getGamma(){
double temp = Math.acos(((Math.pow(a, 2)+Math.pow(b, 2))-Math.pow(c, 2))/(2*b*a));
System.out.println("Gamma = "+temp+" Degrees");
return (temp);// * Math.PI)/180;
}

}

This works, but I need a way to draw the triangle without relying on Graphics2D or drawing it directly with the paintComponent method. Is there a way to do this?

Was it helpful?

Solution

According to the JavaDoc of the Graphics2D class Shapes are rendered according to the following principle:

Shape operations

  1. If the operation is a draw(Shape) operation, then the createStrokedShape method on the current Stroke attribute in the Graphics2D context is used to construct a new Shape object that contains the outline of the specified Shape.

  2. The Shape is transformed from user space to device space using the current Transform in the Graphics2D context.

  3. The outline of the Shape is extracted using the getPathIterator method of Shape, which returns a PathIterator object that iterates along the boundary of the Shape.

  4. If the Graphics2D object cannot handle the curved segments that the PathIterator object returns then it can call the alternate getPathIterator method of Shape, which flattens the Shape.

  5. The current Paint in the Graphics2D context is queried for a PaintContext, which specifies the colors to render in device space.

In short, this means that the Graphics2D.draw(Shape) method will call your TraingleShape.getPathIterator(AffineTransform) method and use the returned PathIterator object in order to find which points to draw lines between.

As such, you will likely be required to implement your own PathIterator implementation that corresponds to your TriangleShape implementation.

The above solution may however be more complex then it needs to be. An alternative would be to look into the Path2D class which allows you to easily specify arbitrary shapes using simple operations such as lineTo(x,y). Since this class implements the Shape interface you could allow your TriangleShape class to extend this class, or just delegate to it. Here is an example of using the GeneralPath class, which works in a similar way to Path2D: http://www.roseindia.net/java/example/java/swing/graphics2D/general-path.shtml

It does however depend on your particular assignment whether this would be an acceptable solution or not.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top