English 中文(简体)
Creating a Squircle
原标题:

I m a first year programmer. I m trying to create a squircle. (square with round corners).

So far i have managed to get. I have been given the constants of a,b and r. If anyone could help i would be really thankful. I m a total noob to this. So be nice :)

package squircle;

import java.awt.*;
import javax.swing.*;
import java.lang.Math;

public class Main extends javax.swing.JApplet {

  public void paint(Graphics g){

   // (x-a)^4  +  (y-b)^4  = r^4

   //    y =   quadroot( r^4 - (x-a)^4  + b)     
   // x values must fall within   a-r < x < a+r

    int[] xPoints = new int[200];
    int[] yPoints = new int[200];
    int[] mypoints = new int[200];

    for(int c = 0; c <200; c++){

       int a = 100;
       int r = 100;
       int b = 100;
       double x = c ;


       double temp = (r*r*r*r);
       double temp2 = x-a;
       double temp3 = ((temp2)*(temp2)*(temp2)*(temp2));
       double temp6 = Math.sqrt(temp-temp3);
       double y = (Math.sqrt(temp6) + b );
       double z = (y*-1)+300;

       mypoints[c]=(int)z;

    // if (c>100){
    //     y = y*1;
    // }
    // else if(c<100){
    //     y = y*1;
    // }

       xPoints[c]=(int)x;
       yPoints[c]=(int)y;


    // change the equation to find x co-ordinates 
    // change it to find y co-ordinates. 

    // r is the minor radius     
    // (a,b) is the location of the centre

    // a = 100
    // b = 100
    // r = 100
    // x value must fall within  0 or 200

    }

    g.drawPolygon(xPoints, yPoints, xPoints.length);
    g.drawPolygon(xPoints, (mypoints), xPoints.length);
  }
}
问题回答

Is it homework or is there some other reason why you re not using Graphics#drawRoundRect()?

If you are submitting this as homework there are some elements of style that may help you. What are the roles of 200, 100 and 300? These are "magic constants" which should be avoided. Are they related or is it just chance that they have these values? Suggest you use symbols such as:

int NPOINTS = 200;

or

double radius = 100.0

That would reveal whether the 300 was actually the value you want. I haven t checked.

Personally I wouldn t write

y*-1

but

-y

as it s too easy to mistype the former.

I would also print out the 200 points as floats and see if you can tell by eye where the error is. It s highly likely that the spurious lines are either drawn at the start or end of the calculation - it s easy to make "end-effect" errors where exactly one point is omitted or calculated twice.

Also it s cheap to experiment. Try iterating c from 0 to 100. or 0 to 10, or 0 to 198 or 1 to 200. Does your spurious line/triangle always occur?

UPDATE Here is what I think is wrong and how to tackle it. You have made a very natural graphics error and a fence-post error (http://en.wikipedia.org/wiki/Off-by-one_error) and it s hard to detect what is wrong because your variable names are poorly chosen.

What is mypoints? I believe it is the bottom half of the squircle - if you had called it bottomHalf then those replying woulod have spotted the problem quicker :-).

Your graphics problem is that you are drawing TWO HALF-squircles. Your are drawing CLOSED curves - when you get to the last point (c==199) the polygon is closed by drawing back to c==0. That makes a D-shape. You have TWO D-shapes, one with the bulge UP and one DOWN. Each has a horizontal line closing the polygon.

Your fence-post error is that you are drawing points from 0 to 199. For the half-squircle you want to draw from 0 to 200. That s 201 points! The loss of one point means that you have a very slightly sloping line. The bottom lines slopes in tghe opposite direction from the top. That gives you a very then wedge shape, which you refer to as a triangle. I m guessing that your triangle is not actually closed but like a slice from a pie but very then/sharp.

(The code below could be prettier and more compact. However it is often useful to break symmetrical problems into quadrants or octants. It would also be interesting to use an anngle to sweep out the polygon).

You actually want ONE polygon. The code should be something like:

int NQUADRANT = 100;
int NPOINTS = 4*NQUADRANT ; // closed polygon
double[] xpoints = new double[NPOINTS];
double[] ypoints = new double[NPOINTS];

Your squircle is at 100, 100 with radius 100. I have chosen different values here to emphasize they aren t related. By using symbolic names you can easily vary them.

double xcenter = 500.0;
double ycentre = 200.0;
double radius = 100.;

double deltax = radius/(double) NQUADRANT;
// let s assume squircle is centered on 0,0 and add offsets later
// this code is NOT complete or correct but should show the way
// I might have time later
for (int i = 0; i < NPOINTS; i++) {

if (i < NQUADRANT) {
    double x0 = -radius + i* deltax;
    double y0 = fourthRoot(radius, x0);
    x[i] = x0+xcenter;
    y[i] = y0+ycenter;

}else if (i < 2*NQUADRANT) {
    double x0 = (i-NQUADRANT)* deltax;
    double y0 = fourthRoot(radius, x0);
    x[i] = x0+xcenter;
    y[i] = y0+ycenter;
}else if (i < 3*NQUADRANT) {
    double x0 = (i-2*NQUADRANT)* deltax;
    double y0 = -fourthRoot(radius, x0);
    x[i] = x0+xcenter;
    y[i] = y0+ycenter;
}else {
    double x0 = -radius + (i-3*NQUADRANT)* deltax;
    double y0 = -fourthRoot(radius, x0);
    x[i] = x0+xcenter;
    y[i] = y0+ycenter;
}

}
// draw single polygon

private double fourthRoot(double radius, double x) {
    return Math.sqrt(Math.sqrt(radius*radius*radius*radius - x*x*x*x));
}

There is a javascript version here. You can view the source and "compare notes" to potentially see what you are doing wrong.

Ok, upon further investigation here is why you are getting the "triangle intersecting it". When you drawPolygon the points are drawn and the last point connects the first point, closing the points and making the polygon. Since you draw one half it is drawn (then connected to itself) and then the same happens for the other side.

As a test of this change your last couple lines to this:

  for( int i = 0; i < yPoints.length; i++ ) {
   g.drawString( "*", xPoints[ i ], yPoints[ i ] );
  }

  for( int i = 0; i < mypoints.length; i++ ) {
   g.drawString( "*", xPoints[ i ], mypoints[ i ] );
  }

//  g.drawPolygon( xPoints, yPoints, xPoints.length );
//  g.drawPolygon( xPoints, ( mypoints ), xPoints.length );

It is a little crude, but I think you ll get the point. There are lots of solutions out there, personally I would try using an array of the Point class and then sort it when done, but I don t know the specifics of what you can and can not do.

Wow, are you guys overthinking this, or what! Why not just use drawLine() four times to draw the straight parts of the rectangle and then use drawArc() to draw the rounded corners?





相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签